package com.imyuanma.qingyun.lowcode.factory;

import com.imyuanma.qingyun.common.util.CollectionUtil;
import com.imyuanma.qingyun.common.util.JsonUtil;
import com.imyuanma.qingyun.common.util.StringUtil;
import com.imyuanma.qingyun.interfaces.common.model.enums.EYesOrNoEnum;
import com.imyuanma.qingyun.lowcode.model.bo.*;
import com.imyuanma.qingyun.lowcode.model.bo.ui.LcpPageConfig;
import com.imyuanma.qingyun.lowcode.model.data.LcpDbColumnDO;
import com.imyuanma.qingyun.lowcode.model.data.LcpDbTableDO;
import com.imyuanma.qingyun.lowcode.model.data.LcpGenerateFieldDO;
import com.imyuanma.qingyun.lowcode.model.data.LcpGenerateMainDO;
import com.imyuanma.qingyun.lowcode.model.enums.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 代码生成业务模型工厂
 *
 * @author wangjy
 * @date 2022/05/04 16:33:54
 */
public class GenerateBOFactory {

    /**
     * 代码生成DB对象转BO对象
     *
     * @param generateMainDO
     * @param fieldDOList
     * @return
     */
    public static GenerateMainBO buildGenerateMainBO(LcpGenerateMainDO generateMainDO, List<LcpGenerateFieldDO> fieldDOList) {
        GenerateMainBO generateMainBO = new GenerateMainBO();
        generateMainBO.setId(generateMainDO.getId());
        generateMainBO.setName(generateMainDO.getName());
        generateMainBO.setTableName(generateMainDO.getTableName());
        generateMainBO.setClassName(generateMainDO.getClassName());
        generateMainBO.setPackagePath(generateMainDO.getPackagePath());
        generateMainBO.setModuleName(generateMainDO.getModuleName());
        generateMainBO.setSavePath(generateMainDO.getSavePath());
        generateMainBO.setAuthor(generateMainDO.getAuthor());
        generateMainBO.setFormLabelPosition(generateMainDO.getFormLabelPosition());
        generateMainBO.setFormLabelWidth(generateMainDO.getFormLabelWidth());
        generateMainBO.setGlobalCss(generateMainDO.getGlobalCss());
        generateMainBO.setGlobalJs(generateMainDO.getGlobalJs());
        if (StringUtil.isNotBlank(generateMainDO.getExtInfo())) {
            GenerateMainExtBO mainExtBO = JsonUtil.toBean(generateMainDO.getExtInfo(), GenerateMainExtBO.class);
            if (mainExtBO.getButtonBarConfig() == null) {
                mainExtBO.setButtonBarConfig(GenerateButtonBarConfigBO.newInstance());
            }
            if (mainExtBO.getTableRowButtonConfig() == null) {
                mainExtBO.setTableRowButtonConfig(GenerateButtonBarConfigBO.newInstance());
            }
            if (CollectionUtil.isEmpty(mainExtBO.getJsLinkList())) {
                mainExtBO.setJsLinkList(Collections.singletonList(JsLinkBO.buildDefault()));
            }
            if (CollectionUtil.isEmpty(mainExtBO.getCssLinkList())) {
                mainExtBO.setCssLinkList(Collections.singletonList(CssLinkBO.buildDefault()));
            }
            if (mainExtBO.getSearchConditionList() == null) {
                mainExtBO.setSearchConditionList(new ArrayList<>());
            }
            generateMainBO.setExtInfo(mainExtBO);
        }
        if (StringUtil.isNotBlank(generateMainDO.getFormPageConfig())) {
            LcpPageConfig formPage = JsonUtil.toBean(generateMainDO.getExtInfo(), LcpPageConfig.class);
            generateMainBO.setFormPageConfig(formPage);
        }
        if (fieldDOList != null) {
            generateMainBO.setFieldList(fieldDOList.stream().map(GenerateBOFactory::buildGenerateFieldBO).collect(Collectors.toList()));
        }
        return generateMainBO;
    }

    // 构造字段BO对象
    public static GenerateFieldBO buildGenerateFieldBO(LcpGenerateFieldDO lcpGenerateFieldDO) {
        GenerateFieldBO generateFieldBO = new GenerateFieldBO();
        generateFieldBO.setId(lcpGenerateFieldDO.getId());
        generateFieldBO.setGenerateId(lcpGenerateFieldDO.getGenerateId());
        generateFieldBO.setFieldDbName(lcpGenerateFieldDO.getFieldDbName());
        generateFieldBO.setFieldDbRemark(lcpGenerateFieldDO.getFieldDbRemark());
        generateFieldBO.setFieldDbType(lcpGenerateFieldDO.getFieldDbType());
        generateFieldBO.setFieldDbLength(lcpGenerateFieldDO.getFieldDbLength());
        generateFieldBO.setFieldDbNotNull(lcpGenerateFieldDO.getFieldDbNotNull());
        generateFieldBO.setFieldDbKey(lcpGenerateFieldDO.getFieldDbKey());
        generateFieldBO.setFieldJavaName(lcpGenerateFieldDO.getFieldJavaName());
        generateFieldBO.setFieldJavaType(lcpGenerateFieldDO.getFieldJavaType());
        generateFieldBO.setSupportImport(lcpGenerateFieldDO.getSupportImport());
        generateFieldBO.setSupportExport(lcpGenerateFieldDO.getSupportExport());
        generateFieldBO.setListColumnShow(lcpGenerateFieldDO.getListColumnShow());
        generateFieldBO.setListColumnOrder(lcpGenerateFieldDO.getListColumnOrder());
        generateFieldBO.setListColumnFixed(lcpGenerateFieldDO.getListColumnFixed());
        generateFieldBO.setListColumnWidth(lcpGenerateFieldDO.getListColumnWidth());
        generateFieldBO.setListColumnSort(lcpGenerateFieldDO.getListColumnSort());
        generateFieldBO.setListHeaderTitle(lcpGenerateFieldDO.getListHeaderTitle());
        generateFieldBO.setListHeaderAlign(lcpGenerateFieldDO.getListHeaderAlign());
        generateFieldBO.setListHeaderTips(lcpGenerateFieldDO.getListHeaderTips());
        generateFieldBO.setListValueAlign(lcpGenerateFieldDO.getListValueAlign());
        generateFieldBO.setListValueFormat(lcpGenerateFieldDO.getListValueFormat());
        generateFieldBO.setListQueryCondition(lcpGenerateFieldDO.getListQueryCondition());
        generateFieldBO.setFormColumnShow(lcpGenerateFieldDO.getFormColumnShow());
        generateFieldBO.setFormColumnOrder(lcpGenerateFieldDO.getFormColumnOrder());
        generateFieldBO.setFormColumnGridWidth(lcpGenerateFieldDO.getFormColumnGridWidth());
        generateFieldBO.setFormControlType(lcpGenerateFieldDO.getFormControlType());
        generateFieldBO.setFormControlDefault(lcpGenerateFieldDO.getFormControlDefault());
        generateFieldBO.setFormControlTitle(lcpGenerateFieldDO.getFormControlTitle());
        generateFieldBO.setFormControlPlaceholder(lcpGenerateFieldDO.getFormControlPlaceholder());
        generateFieldBO.setFormControlTips(lcpGenerateFieldDO.getFormControlTips());
        if (StringUtil.isNotBlank(lcpGenerateFieldDO.getFormColumnShowConfig())) {
            generateFieldBO.setFormColumnShowConfig(JsonUtil.toBean(lcpGenerateFieldDO.getFormColumnShowConfig(), GenerateFormColumnShowConfigBO.class));
        }
        if (StringUtil.isNotBlank(lcpGenerateFieldDO.getFormControlDataSource())) {
            generateFieldBO.setFormControlDataSource(JsonUtil.toBean(lcpGenerateFieldDO.getFormControlDataSource(), GenerateControlDataSourceBO.class));
        }
        if (StringUtil.isNotBlank(lcpGenerateFieldDO.getFormControlCheckRule())) {
            generateFieldBO.setFormControlCheckRule(JsonUtil.toBean(lcpGenerateFieldDO.getFormControlCheckRule(), GenerateControlCheckRuleBO.class));
        }
        if (StringUtil.isNotBlank(lcpGenerateFieldDO.getFormControlConfig())) {
            generateFieldBO.setFormControlConfig(JsonUtil.toBean(lcpGenerateFieldDO.getFormControlConfig(), GenerateControlConfigBO.class));
        }
        return generateFieldBO;
    }

    /**
     * 构造代码生成配置对象
     *
     * @param table      表信息
     * @param columnList 字段信息列表
     * @return
     */
    public static GenerateMainBO buildGenerateMainBO(LcpDbTableDO table, List<LcpDbColumnDO> columnList) {
        GenerateMainBO generateMainBO = new GenerateMainBO();
//        generateMainBO.setId();
        generateMainBO.setName(table.getTableComment());
        generateMainBO.setTableName(table.getTableName());
        generateMainBO.setClassName(StringUtil.toFirstUpperCamel(table.getTableName()));
        generateMainBO.setPackagePath("com.imyuanma.qingyun");
        generateMainBO.setModuleName("");
        generateMainBO.setSavePath("C:\\qingYunCodeGenerate");
        generateMainBO.setAuthor("YuanMaKeJi");
        generateMainBO.setFormLabelPosition("left");
        generateMainBO.setFormLabelWidth("120px");
        generateMainBO.setGlobalCss("");
        generateMainBO.setGlobalJs("");
        // 扩展配置
        generateMainBO.setExtInfo(buildGenerateMainExtBO());
        generateMainBO.setFieldList(columnList.stream().map(item -> GenerateBOFactory.buildGenerateFieldBO(item)).collect(Collectors.toList()));
        // 字段初始化完成后再次填充全局配置
        fillGenerateMainBOAfterFieldInit(generateMainBO);
        return generateMainBO;
    }

    /**
     * 字段初始化完成后再次填充全局配置
     *
     * @param generateMainBO
     */
    private static void fillGenerateMainBOAfterFieldInit(GenerateMainBO generateMainBO) {
        // 设置默认的查询条件
        generateMainBO.getExtInfo().setSearchConditionList(
                generateMainBO.getFieldList().stream()
                        .filter(item -> Objects.nonNull(item.getListQueryCondition()) && !ELcpQueryConditionTypeEnum.NO.getType().equals(item.getListQueryCondition()))
                        .map(SearchConditionItem::build)
                        .collect(Collectors.toList())
        );
    }

    // 构造代码生成扩展信息
    private static GenerateMainExtBO buildGenerateMainExtBO() {
        GenerateMainExtBO generateMainExtBO = new GenerateMainExtBO();
//        generateMainExtBO.setId();
        generateMainExtBO.setTraceType(1);
        generateMainExtBO.setWebDomain("/");
        generateMainExtBO.setSupportImportExcel(EYesOrNoEnum.NO.getCode());
        generateMainExtBO.setSupportExportExcel(EYesOrNoEnum.NO.getCode());
        generateMainExtBO.setModelExtendsType(null);
        generateMainExtBO.setTableFirstColumnType(ELcpTableColumnTypeEnum.CHECKBOX.getType());
        generateMainExtBO.setPageSize(10);
        List<String> rowBtnList = new ArrayList<>();
        rowBtnList.add(ELcpTableRowBtnEnum.EDIT.getType());
        rowBtnList.add(ELcpTableRowBtnEnum.DELETE.getType());
        // 表格行按钮
        generateMainExtBO.setTableRowOperateButtonList(rowBtnList);
        // 表格行按钮
        generateMainExtBO.setTableRowButtonConfig(buildTableRowButtonConfig());
        // 按钮栏
        generateMainExtBO.setButtonBarConfig(buildButtonBarConfig());
        generateMainExtBO.setTableDataUrl("");
        generateMainExtBO.setDetailUrl("");
        generateMainExtBO.setInsertUrl("");
        generateMainExtBO.setUpdateUrl("");
        generateMainExtBO.setDeleteUrl("");
        generateMainExtBO.setJsLinkList(Collections.singletonList(JsLinkBO.buildDefault()));
        generateMainExtBO.setCssLinkList(Collections.singletonList(CssLinkBO.buildDefault()));
        // 查询条件
//        generateMainExtBO.setSearchConditionList();
        return generateMainExtBO;
    }

    /**
     * 构造表格行按钮
     *
     * @return
     */
    private static GenerateButtonBarConfigBO buildTableRowButtonConfig() {
        GenerateButtonBarConfigBO buttonBarConfigBO = GenerateButtonBarConfigBO.newInstance();
        buttonBarConfigBO.addButton(LcpButtonBO.of(ELcpInnerButtonEnum.TABLE_ROW_EDIT));
        buttonBarConfigBO.addButton(LcpButtonBO.of(ELcpInnerButtonEnum.TABLE_ROW_DELETE));
        return buttonBarConfigBO;
    }

    /**
     * 构造视图按钮栏
     *
     * @return
     */
    private static GenerateButtonBarConfigBO buildButtonBarConfig() {
        GenerateButtonBarConfigBO buttonBarConfigBO = GenerateButtonBarConfigBO.newInstance();
        buttonBarConfigBO.addButton(LcpButtonBO.of(ELcpInnerButtonEnum.LIST_ADD));
        buttonBarConfigBO.addButton(LcpButtonBO.of(ELcpInnerButtonEnum.LIST_DELETE));
        buttonBarConfigBO.addButton(LcpButtonBO.of(ELcpInnerButtonEnum.LIST_RELOAD));
        return buttonBarConfigBO;
    }

    /**
     * 构造代码生成字段配置对象
     *
     * @param column 字段信息
     * @return
     */
    public static GenerateFieldBO buildGenerateFieldBO(LcpDbColumnDO column) {
        GenerateFieldBO generateFieldBO = new GenerateFieldBO();
//        generateFieldBO.setId();
//        generateFieldBO.setGenerateId();

        // 填充基础属性
        fillFieldBaseAttr(generateFieldBO, column);

        // 填充视图相关配置
        fillFieldViewAttr(generateFieldBO, column);

        // 填充表单相关配置
        fillFieldFormAttr(generateFieldBO, column);


        return generateFieldBO;
    }

    /**
     * 填充基础属性
     *
     * @param generateFieldBO
     * @param column
     */
    private static void fillFieldBaseAttr(GenerateFieldBO generateFieldBO, LcpDbColumnDO column) {
        generateFieldBO.setFieldDbName(column.getColumnName());
        generateFieldBO.setFieldDbRemark(column.getRemark());
        generateFieldBO.setFieldDbType(column.getDataType());
        generateFieldBO.setFieldDbLength(column.getLength());
        generateFieldBO.setFieldDbNotNull(column.getNotNull());
        generateFieldBO.setFieldDbKey(column.getColumnKey());
        generateFieldBO.setFieldJavaName(StringUtil.toCamel(column.getColumnName()));
        // 字段类型枚举
        ELcpColumnTypeEnum columnTypeEnum = ELcpColumnTypeEnum.ofOrDefault(column.getDataType());
        generateFieldBO.setFieldJavaType(columnTypeEnum.getJavaType());
        generateFieldBO.setSupportImport(EYesOrNoEnum.YES.getCode());
        generateFieldBO.setSupportExport(EYesOrNoEnum.YES.getCode());
        // 比较大的文本默认不支持导入导出
        if (columnTypeEnum.isText() ||
                (columnTypeEnum.isLengthLimitStringType() && column.getLength() > 2000)) {
            generateFieldBO.setSupportImport(EYesOrNoEnum.NO.getCode());
            generateFieldBO.setSupportExport(EYesOrNoEnum.NO.getCode());
        }
    }

    /**
     * 填充视图属性
     *
     * @param generateFieldBO
     * @param column
     */
    private static void fillFieldViewAttr(GenerateFieldBO generateFieldBO, LcpDbColumnDO column) {
        ELcpColumnTypeEnum columnTypeEnum = ELcpColumnTypeEnum.ofOrDefault(column.getDataType());
        // 比较大的文本默认不显示
        if (columnTypeEnum.isText() ||
                (columnTypeEnum.isLengthLimitStringType() && column.getLength() > 2000)) {
            generateFieldBO.setListColumnShow(EYesOrNoEnum.NO.getCode());
        } else if (!"create_time".equals(generateFieldBO.getFieldDbName()) && generateFieldBO.isBaseDOField()) {
            generateFieldBO.setListColumnShow(EYesOrNoEnum.NO.getCode());
        } else {
            generateFieldBO.setListColumnShow(EYesOrNoEnum.YES.getCode());
        }
        generateFieldBO.setListColumnOrder(column.getPosition() != null ? column.getPosition() * 10 : 1000);
        generateFieldBO.setListColumnFixed("no");
        if (columnTypeEnum == ELcpColumnTypeEnum.DATETIME || columnTypeEnum == ELcpColumnTypeEnum.TIMESTAMP) {
            generateFieldBO.setListColumnWidth("155");
        } else if (columnTypeEnum.isNumberType()) {
            generateFieldBO.setListColumnWidth("100");
        } else if (column.getLength() != null && column.getLength() > 250) {
            generateFieldBO.setListColumnWidth("250");
        } else {
            generateFieldBO.setListColumnWidth("180");
        }
        if (columnTypeEnum.isNumberType() || columnTypeEnum.isDateType()) {
            generateFieldBO.setListColumnSort(EYesOrNoEnum.YES.getCode());
        } else {
            generateFieldBO.setListColumnSort(EYesOrNoEnum.NO.getCode());
        }

        generateFieldBO.setListHeaderTitle(simpleRemark(column.getRemark()));
        generateFieldBO.setListHeaderAlign("left");
        generateFieldBO.setListHeaderTips("");
        generateFieldBO.setListValueAlign("left");
        generateFieldBO.setListValueFormat(ELcpShowFormatEnum.TEXT.getText());
        // 查询类型
        if (column.getColumnName().toLowerCase().endsWith("id")) {
            generateFieldBO.setListQueryCondition(ELcpQueryConditionTypeEnum.EQ.getType());
        } else if (column.getColumnName().toLowerCase().endsWith("name")) {
            generateFieldBO.setListQueryCondition(ELcpQueryConditionTypeEnum.LIKE.getType());
        } else if (column.getColumnName().toLowerCase().endsWith("time")) {
            generateFieldBO.setListQueryCondition(ELcpQueryConditionTypeEnum.BETWEEN_AND.getType());
        } else {
            generateFieldBO.setListQueryCondition(ELcpQueryConditionTypeEnum.NO.getType());
        }
    }

    /**
     * 填充表单属性
     *
     * @param generateFieldBO
     * @param column
     */
    private static void fillFieldFormAttr(GenerateFieldBO generateFieldBO, LcpDbColumnDO column) {
        ELcpColumnTypeEnum columnTypeEnum = ELcpColumnTypeEnum.ofOrDefault(column.getDataType());
        if (generateFieldBO.isBaseDOField()) {
            generateFieldBO.setFormColumnShow(EYesOrNoEnum.NO.getCode());
        } else {
            generateFieldBO.setFormColumnShow(EYesOrNoEnum.YES.getCode());
        }
        generateFieldBO.setFormColumnOrder(column.getPosition() != null ? column.getPosition() * 10 : 1000);
        generateFieldBO.setFormColumnGridWidth(24);
        // 控件类型
        if (columnTypeEnum.isDateType()) {
            // 时间
            generateFieldBO.setFormControlType(ELcpFormControlTypeEnum.DATE.getType());
        } else if (columnTypeEnum.isText()) {
            // 大文本
            generateFieldBO.setFormControlType(ELcpFormControlTypeEnum.TEXTAREA.getType());
        } else if (columnTypeEnum.isLengthLimitStringType() && column.getLength() > 2000) {
            // 大文本
            generateFieldBO.setFormControlType(ELcpFormControlTypeEnum.TEXTAREA.getType());
        } else if (columnTypeEnum.isNumberType() && !generateFieldBO.isPrimaryKey()) {
            // 数字
            generateFieldBO.setFormControlType(ELcpFormControlTypeEnum.NUMBER.getType());
        } else {
            // 普通输入框
            generateFieldBO.setFormControlType(ELcpFormControlTypeEnum.INPUT.getType());
        }
        generateFieldBO.setFormControlDefault(null);
        generateFieldBO.setFormControlTitle(simpleRemark(column.getRemark()));
        generateFieldBO.setFormControlPlaceholder("");
        generateFieldBO.setFormControlTips("");
        // 显隐规则
        generateFieldBO.setFormColumnShowConfig(buildColumnShowConfig(generateFieldBO));
        // 数据源配置
        generateFieldBO.setFormControlDataSource(buildControlDataSource(generateFieldBO));
        // 表单校验
        generateFieldBO.setFormControlCheckRule(buildControlCheckRule(generateFieldBO));
        // 其他
        generateFieldBO.setFormControlConfig(buildControlConfig(generateFieldBO));
    }

    /**
     * 表单项展示(交互)配置
     *
     * @param generateFieldBO
     * @return
     */
    private static GenerateFormColumnShowConfigBO buildColumnShowConfig(GenerateFieldBO generateFieldBO) {
        GenerateFormColumnShowConfigBO generateFormColumnShowConfigBO = new GenerateFormColumnShowConfigBO();
        generateFormColumnShowConfigBO.setShowType(ELcpFormItemShowTypeEnum.SHOW.getType());
        generateFormColumnShowConfigBO.setDisableType(ELcpFormItemDisableTypeEnum.NOT_DISABLE.getType());
        return generateFormColumnShowConfigBO;
    }

    /**
     * 字段其他配置
     *
     * @param generateFieldBO
     * @return
     */
    private static GenerateControlConfigBO buildControlConfig(GenerateFieldBO generateFieldBO) {
        GenerateControlConfigBO controlConfigBO = new GenerateControlConfigBO();
        controlConfigBO.setMin(0L);
        controlConfigBO.setMax((long) Integer.MAX_VALUE);
        controlConfigBO.setStep(1L);
        controlConfigBO.setNumberControls(EYesOrNoEnum.NO.getCode());
        controlConfigBO.setRows(3);
        controlConfigBO.setAutosize(EYesOrNoEnum.NO.getCode());
        controlConfigBO.setYesValue(EYesOrNoEnum.YES.getCodeAsStr());
        controlConfigBO.setNoValue(EYesOrNoEnum.NO.getCodeAsStr());
        return controlConfigBO;
    }

    /**
     * 构造数据源配置
     *
     * @param generateFieldBO
     * @return
     */
    private static GenerateControlDataSourceBO buildControlDataSource(GenerateFieldBO generateFieldBO) {
        GenerateControlDataSourceBO generateControlDataSourceBO = new GenerateControlDataSourceBO();
        generateControlDataSourceBO.setDataType(ELcpFormItemDataSourceTypeEnum.NO.getType());
        generateControlDataSourceBO.setDataUrl("");
        generateControlDataSourceBO.setKeyField("key");
        generateControlDataSourceBO.setValueField("value");
        generateControlDataSourceBO.setOptionItemList(new ArrayList<>());
        return generateControlDataSourceBO;
    }

    /**
     * 构造表单项校验规则
     *
     * @param generateFieldBO
     * @return
     */
    private static GenerateControlCheckRuleBO buildControlCheckRule(GenerateFieldBO generateFieldBO) {
        ELcpColumnTypeEnum columnTypeEnum = ELcpColumnTypeEnum.ofOrDefault(generateFieldBO.getFieldDbType());
        GenerateControlCheckRuleBO generateControlCheckRuleBO = new GenerateControlCheckRuleBO();
        // 校验规则
        generateControlCheckRuleBO.setCheckRuleList(new ArrayList<>());
        // 必填则设置必填校验
        if (EYesOrNoEnum.YES.getCode().equals(generateFieldBO.getFieldDbNotNull())) {
            generateControlCheckRuleBO.getCheckRuleList().add(CheckRuleItem.build(ELcpFormControlCheckEnum.ErrEmpty, generateFieldBO));
        }
        // 数字则设置数字校验
        if (columnTypeEnum.isNumberType()) {
            generateControlCheckRuleBO.getCheckRuleList().add(CheckRuleItem.build(ELcpFormControlCheckEnum.ErrNumber, generateFieldBO));
        }
        // 字符串则校验长度
        if (columnTypeEnum.isLengthLimitStringType()) {
            generateControlCheckRuleBO.getCheckRuleList().add(CheckRuleItem.build(ELcpFormControlCheckEnum.ErrLength, generateFieldBO));
        }
        return generateControlCheckRuleBO;
    }

    /**
     * 简单备注
     *
     * @param remark
     * @return
     */
    private static String simpleRemark(String remark) {
        if (StringUtil.isBlank(remark) || !remark.contains(",")) {
            return remark;
        }
        return remark.split(",")[0];
    }
}
